home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / readers / nn-tk.001 / nn-tk~ / nn / keymap.c < prev    next >
C/C++ Source or Header  |  1995-07-28  |  23KB  |  1,025 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Keyboard (re)mapping
  5.  */
  6.  
  7. #include "config.h"
  8. #include "keymap.h"
  9. #include "nn_term.h"
  10.  
  11. import int data_bits;
  12.  
  13. /*
  14.  * KEY MAP LAYOUT:
  15.  *    128 normal ASCII chars
  16.  *    0200 -- unused
  17.  *    4 arrow keys #up/down/left/right
  18.  *    10 multi keys #0-#9
  19.  *    17 spare keys
  20.  *    95 national 8-bit characters (8859/x)
  21.  *    0377 is unused (since we must be able to test c<KEY_MAP_SIZE)
  22.  *
  23.  *    The encoding of the keymap arrays are performed in
  24.  *    keymap.c (initialization + key_name/parse_key)
  25.  */
  26.  
  27. /* in keymap.h, MULTI_KEYS include ARROW_KEYS for term.c */
  28. #undef MULTI_KEYS
  29.  
  30. #define NORMAL_KEYS    129    /* include 0200 for convenience */
  31. #define ARROW_KEYS    4
  32. #define MULTI_KEYS    16
  33. #define SPARE_KEYS    11
  34. #define NATIONAL_KEYS    96
  35. #define KEY_MAP_SIZE    255
  36.  
  37. /*
  38.  * standard keyboard mapping for more()
  39.  *
  40.  *    redraw            ^L, ^R
  41.  *    continue        space
  42.  *    repeat message        ^P
  43.  *    help            ?
  44.  *    shell escape        !
  45.  *    version            V
  46.  *    extended command    :
  47.  *    quit            Q
  48.  *
  49.  *    save            S, O
  50.  *    save, no header        W
  51.  *    reply            R
  52.  *    follow up        F
  53.  *    mail (forward)        M
  54.  *    cancel            C
  55.  *    unsubscribe        U
  56.  *    group overview        Y
  57.  *    print article        P
  58.  *    kill handling        K
  59.  *
  60.  *    update, goto next group    X
  61.  *    no update, next group    q, Z
  62.  *    return to menu        =
  63.  *    prev article        p
  64.  *    goto group        G
  65.  *
  66.  *    line forward        CR/NL
  67.  *    half page forward    d/^D
  68.  *    half page back        u/^U
  69.  *    full page back        BS, DEL, (up arrow)
  70.  *    goto line        g
  71.  *    goto match        /
  72.  *    next match        .
  73.  *
  74.  *    select subject        N, *
  75.  *
  76.  *    header            h
  77.  *    digest header        H
  78.  *    top            t
  79.  *    last page        $
  80.  *    leave article        l
  81.  *    leave article to next    L
  82.  *    next article        n
  83.  *    kill subject        k
  84.  *
  85.  *    rot13            D
  86.  *    compress        c
  87.  */
  88.  
  89. export int more_key_map[KEY_MAP_SIZE] = {
  90.  
  91. /* NUL ^@ */    K_UNBOUND,
  92. /* SOH ^A */    K_UNBOUND,
  93. /* STX ^B */    K_UNBOUND,
  94. /* ETX ^C */    K_UNBOUND,
  95. /* EOT ^D */        K_NEXT_HALF_PAGE,
  96. /* ENQ ^E */    K_UNBOUND,
  97. /* ACK ^F */    K_UNBOUND,
  98. /* BEL ^G */        K_INVALID,
  99. /* BS  ^H */        K_PREV_PAGE,
  100. /* TAB ^I */        K_SKIP_LINES,
  101. /* NL  ^J */        K_NEXT_LINE,
  102. /* VT  ^K */    K_UNBOUND,
  103. /* FF  ^L */        K_REDRAW,
  104. /* CR  ^M */        K_NEXT_LINE,
  105. /* SO  ^N */    K_UNBOUND,
  106. /* SI  ^O */    K_UNBOUND,
  107. /* DLE ^P */        K_LAST_MESSAGE,
  108. /* DC1 ^Q */    K_UNBOUND,
  109. /* DC2 ^R */        K_REDRAW,
  110. /* DC3 ^S */    K_UNBOUND,
  111. /* DC4 ^T */    K_UNBOUND,
  112. /* NAK ^U */        K_PREV_HALF_PAGE,
  113. /* SYN ^V */        K_NEXT_PAGE,
  114. /* ETB ^W */    K_UNBOUND,
  115. /* CAN ^X */    K_UNBOUND,
  116. /* EM  ^Y */    K_UNBOUND,
  117. /* SUB ^Z */    K_UNBOUND,
  118. /* ESC ^[ */    K_UNBOUND,
  119. /* FS  ^\ */    K_UNBOUND,
  120. /* GS  ^] */    K_UNBOUND,
  121. /* RS  ^^ */    K_UNBOUND,
  122. /* US  ^_ */    K_UNBOUND,
  123. /* SP  */        K_CONTINUE,
  124. /* !   */        K_SHELL,
  125. /* "   */    K_UNBOUND,
  126. /* #   */    K_UNBOUND,
  127. /* $   */        K_LAST_PAGE,
  128. /* %   */        K_PREVIEW,
  129. /* &   */    K_UNBOUND,
  130. /* '   */    K_UNBOUND,
  131. /* (   */    K_UNBOUND,
  132. /* )   */    K_UNBOUND,
  133. /* *   */        K_SELECT_SUBJECT,
  134. /* +   */    K_UNBOUND,
  135. /* ,   */    K_UNBOUND,
  136. /* -   */    K_UNBOUND,
  137. /* .   */        K_NEXT_MATCH,
  138. /* /   */        K_GOTO_MATCH,
  139. /* 0   */    K_UNBOUND,
  140. /* 1   */    K_UNBOUND,
  141. /* 2   */    K_UNBOUND,
  142. /* 3   */    K_UNBOUND,
  143. /* 4   */    K_UNBOUND,
  144. /* 5   */    K_UNBOUND,
  145. /* 6   */    K_UNBOUND,
  146. /* 7   */    K_UNBOUND,
  147. /* 8   */    K_UNBOUND,
  148. /* 9   */    K_UNBOUND,
  149. /* :   */         K_EXTENDED_CMD,
  150. /* ;   */    K_UNBOUND,
  151. /* <   */    K_UNBOUND,
  152. /* =   */        K_BACK_TO_MENU,
  153. /* >   */    K_UNBOUND,
  154. /* ?   */        K_HELP,
  155. /* @   */    K_UNBOUND,
  156. /* A   */    K_UNBOUND,
  157. /* B   */    K_UNBOUND,
  158. /* C   */        K_CANCEL,
  159. /* D   */        K_ROT13,
  160. /* E   */    K_UNBOUND,
  161. /* F   */        K_FOLLOW_UP,
  162. /* G   */        K_GOTO_GROUP,
  163. /* H   */        K_FULL_DIGEST,
  164. /* I   */    K_UNBOUND,
  165. /* J   */    K_UNBOUND,
  166. /* K   */        K_KILL_HANDLING,
  167. /* L   */        K_LEAVE_NEXT,
  168. /* M   */        K_MAIL_OR_FORWARD,
  169. /* N   */        K_NEXT_GROUP_NO_UPDATE,
  170. /* O   */        K_SAVE_SHORT_HEADER,
  171. /* P   */        K_PRINT,
  172. /* Q   */         K_QUIT,
  173. /* R   */        K_REPLY,
  174. /* S   */        K_SAVE_FULL_HEADER,
  175. /* T   */    K_UNBOUND,
  176. /* U   */        K_UNSUBSCRIBE,
  177. /* V   */         K_VERSION,
  178. /* W   */        K_SAVE_NO_HEADER,
  179. /* X   */        K_READ_GROUP_UPDATE,
  180. /* Y   */        K_GROUP_OVERVIEW,
  181. /* Z   */        K_BACK_TO_MENU,
  182. /* [   */    K_UNBOUND,
  183. /* \   */    K_UNBOUND,
  184. /* ]   */    K_UNBOUND,
  185. /* ^   */        K_FIRST_PAGE,
  186. /* _   */    K_UNBOUND,
  187. /* `   */    K_UNBOUND,
  188. /* a   */        K_FORW_ARTICLE,
  189. /* b   */        K_BACK_ARTICLE,
  190. /* c   */        K_COMPRESS,
  191. /* d   */        K_NEXT_HALF_PAGE,
  192. /* e   */    K_UNBOUND,
  193. /* f   */        K_FOLLOW_UP,
  194. /* g   */        K_GOTO_LINE,
  195. /* h   */        K_HEADER_PAGE,
  196. /* i   */    K_UNBOUND,
  197. /* j   */    K_UNBOUND,
  198. /* k   */        K_NEXT_SUBJECT,
  199. /* l   */        K_LEAVE_ARTICLE,
  200. /* m   */        K_MAIL_OR_FORWARD,
  201. /* n   */        K_NEXT_ARTICLE,
  202. /* o   */        K_SAVE_SHORT_HEADER,
  203. /* p   */        K_PREVIOUS /* article */,
  204. /* q   */        K_NEXT_GROUP_NO_UPDATE,
  205. /* r   */        K_REPLY,
  206. /* s   */        K_SAVE_FULL_HEADER,
  207. /* t   */        K_FIRST_PAGE,
  208. /* u   */        K_PREV_HALF_PAGE,
  209. /* v   */    K_UNBOUND,
  210. /* w   */        K_SAVE_NO_HEADER,
  211. /* x   */    K_UNBOUND,
  212. /* y   */    K_UNBOUND,
  213. /* z   */    K_UNBOUND,
  214. /* {   */    K_UNBOUND,
  215. /* |   */    K_UNBOUND,
  216. /* }   */    K_UNBOUND,
  217. /* ~   */    K_UNBOUND,
  218. /* DEL */        K_PREV_PAGE,
  219. /* 200 */    K_UNBOUND,
  220. /* up  */        K_PREV_PAGE,
  221. /* down */        K_NEXT_PAGE,
  222. /* left */    K_UNBOUND,
  223. /* right */    K_UNBOUND,
  224. /* #0  */    K_UNBOUND,
  225. /* #1  */    K_UNBOUND,
  226. /* #2  */    K_UNBOUND,
  227. /* #3  */    K_UNBOUND,
  228. /* #4  */    K_UNBOUND,
  229. /* #5  */    K_UNBOUND,
  230. /* #6  */    K_UNBOUND,
  231. /* #7  */    K_UNBOUND,
  232. /* #8  */    K_UNBOUND,
  233. /* #9  */    K_UNBOUND,
  234. /* mouse d1 */   K_M_CONTINUE,
  235. /* mouse d2 */   K_NEXT_SUBJECT,
  236. /* mouse d3 */   K_BACK_TO_MENU,
  237. /* mouse u1 */   K_INVALID,
  238. /* mouse u2 */   K_INVALID,
  239. /* mouse u3 */   K_INVALID
  240. };
  241.  
  242.  
  243.  
  244. /*
  245.  * standard keyboard mappings for menu()
  246.  *
  247.  *    illegal command
  248.  *    redraw            ^L, ^R
  249.  *    continue        space
  250.  *    continue no mark    return, newline
  251.  *    repeat message        ^P
  252.  *    help            ?
  253.  *    shell escape        !
  254.  *    version            V
  255.  *    alternative commands    :
  256.  *    quit            Q
  257.  *
  258.  *    save            S, O
  259.  *    save, no header        W
  260.  *    reply            R
  261.  *    follow up        F
  262.  *    mail (forward)        M
  263.  *    cancel            C
  264.  *    unsubscribe        U
  265.  *    group overview        Y
  266.  *    kill handling        K
  267.  *    junk articles        J
  268.  *
  269.  *    read, then next        X
  270.  *    read, then same        Z
  271.  *    no update, next        N
  272.  *    prev group        P
  273.  *    goto group        G
  274.  *    advance group        A
  275.  *    back group        B
  276.  *
  277.  *    article identifier    a-z 0-9
  278.  *    inverse            @
  279.  *    select current, next    .
  280.  *    next            , (down arrow)
  281.  *    prev            / (up arrow)
  282.  *    select subject        *
  283.  *    range            -
  284.  *    auto select         +
  285.  *
  286.  *    next page        >
  287.  *    prev page        <
  288.  *    first page        ^
  289.  *    last page        $
  290.  *
  291.  *    pre-view article    %
  292.  *
  293.  *    layout            L
  294.  */
  295.  
  296.  
  297. export int menu_key_map[KEY_MAP_SIZE] = {
  298.  
  299. /* NUL ^@ */    K_UNBOUND,
  300. /* SOH ^A */    K_UNBOUND,
  301. /* STX ^B */    K_UNBOUND,
  302. /* ETX ^C */    K_UNBOUND,
  303. /* EOT ^D */    K_UNBOUND,
  304. /* ENQ ^E */    K_UNBOUND,
  305. /* ACK ^F */    K_UNBOUND,
  306. /* BEL ^G */        K_INVALID,
  307. /* BS  ^H */        K_PREV_LINE,
  308. /* TAB ^I */    K_UNBOUND,
  309. /* NL  ^J */        K_CONTINUE_NO_MARK,
  310. /* VT  ^K */    K_UNBOUND,
  311. /* FF  ^L */        K_REDRAW,
  312. /* CR  ^M */        K_CONTINUE_NO_MARK,
  313. /* SO  ^N */    K_UNBOUND,
  314. /* SI  ^O */    K_UNBOUND,
  315. /* DLE ^P */        K_LAST_MESSAGE,
  316. /* DC1 ^Q */    K_UNBOUND,
  317. /* DC2 ^R */        K_REDRAW,
  318. /* DC3 ^S */    K_UNBOUND,
  319. /* DC4 ^T */    K_UNBOUND,
  320. /* NAK ^U */    K_UNBOUND,
  321. /* SYN ^V */        K_NEXT_PAGE,
  322. /* ETB ^W */    K_UNBOUND,
  323. /* CAN ^X */    K_UNBOUND,
  324. /* EM  ^Y */    K_UNBOUND,
  325. /* SUB ^Z */    K_UNBOUND,
  326. /* ESC ^[ */    K_UNBOUND,
  327. /* FS  ^\ */    K_UNBOUND,
  328. /* GS  ^] */    K_UNBOUND,
  329. /* RS  ^^ */    K_UNBOUND,
  330. /* US  ^_ */    K_UNBOUND,
  331. /* SP  */        K_CONTINUE,
  332. /* !   */        K_SHELL,
  333. /* "   */        K_LAYOUT,
  334. /* #   */    K_UNBOUND,
  335. /* $   */        K_LAST_PAGE,
  336. /* %   */        K_PREVIEW,
  337. /* &   */    K_UNBOUND,
  338. /* '   */    K_UNBOUND,
  339. /* (   */        K_OPEN_SUBJECT,
  340. /* )   */        K_CLOSE_SUBJECT,
  341. /* *   */        K_SELECT_SUBJECT,
  342. /* +   */        K_AUTO_SELECT,
  343. /* ,   */        K_NEXT_LINE,
  344. /* -   */        K_SELECT_RANGE,
  345. /* .   */        K_SELECT,
  346. /* /   */        K_PREV_LINE,
  347. /* 0   */    K_ARTICLE_ID + 26,
  348. /* 1   */    K_ARTICLE_ID + 27,
  349. /* 2   */    K_ARTICLE_ID + 28,
  350. /* 3   */    K_ARTICLE_ID + 29,
  351. /* 4   */    K_ARTICLE_ID + 30,
  352. /* 5   */    K_ARTICLE_ID + 31,
  353. /* 6   */    K_ARTICLE_ID + 32,
  354. /* 7   */    K_ARTICLE_ID + 33,
  355. /* 8   */    K_ARTICLE_ID + 34,
  356. /* 9   */    K_ARTICLE_ID + 35,
  357. /* :   */        K_EXTENDED_CMD,
  358. /* ;   */    K_UNBOUND,
  359. /* <   */        K_PREV_PAGE,
  360. /* =   */        K_GOTO_MATCH,
  361. /* >   */        K_NEXT_PAGE,
  362. /* ?   */        K_HELP,
  363. /* @   */        K_SELECT_INVERT,
  364. /* A   */        K_ADVANCE_GROUP,
  365. /* B   */        K_BACK_GROUP,
  366. /* C   */        K_CANCEL,
  367. /* D   */    K_SEL_GROUP,
  368. /* E   */    K_UNBOUND,
  369. /* F   */        K_FOLLOW_UP,
  370. /* G   */        K_GOTO_GROUP,
  371. /* H   */    K_UNBOUND,
  372. /* I   */    K_UNBOUND,
  373. /* J   */        K_JUNK_ARTICLES,
  374. /* K   */        K_KILL_HANDLING,
  375. /* L   */        K_LEAVE_NEXT,
  376. /* M   */        K_MAIL_OR_FORWARD,
  377. /* N   */        K_NEXT_GROUP_NO_UPDATE,
  378. /* O   */        K_SAVE_SHORT_HEADER,
  379. /* P   */        K_PREVIOUS /* group */,
  380. /* Q   */        K_QUIT,
  381. /* R   */        K_REPLY,
  382. /* S   */        K_SAVE_FULL_HEADER,
  383. /* T   */    K_UNBOUND,
  384. /* U   */        K_UNSUBSCRIBE,
  385. /* V   */        K_VERSION,
  386. /* W   */        K_SAVE_NO_HEADER,
  387. /* X   */        K_READ_GROUP_UPDATE,
  388. /* Y   */        K_GROUP_OVERVIEW,
  389. /* Z   */        K_READ_GROUP_THEN_SAME,
  390. /* [   */    K_UNBOUND,
  391. /* \   */    K_UNBOUND,
  392. /* ]   */    K_UNBOUND,
  393. /* ^   */        K_FIRST_PAGE,
  394. /* _   */    K_UNBOUND,
  395. /* `   */    K_UNBOUND,
  396. /* a   */    K_ARTICLE_ID +  0,
  397. /* b   */    K_ARTICLE_ID +  1,
  398. /* c   */    K_ARTICLE_ID +  2,
  399. /* d   */    K_ARTICLE_ID +  3,
  400. /* e   */    K_ARTICLE_ID +  4,
  401. /* f   */    K_ARTICLE_ID +  5,
  402. /* g   */    K_ARTICLE_ID +  6,
  403. /* h   */    K_ARTICLE_ID +  7,
  404. /* i   */    K_ARTICLE_ID +  8,
  405. /* j   */    K_ARTICLE_ID +  9,
  406. /* k   */    K_ARTICLE_ID + 10,
  407. /* l   */    K_ARTICLE_ID + 11,
  408. /* m   */    K_ARTICLE_ID + 12,
  409. /* n   */    K_ARTICLE_ID + 13,
  410. /* o   */    K_ARTICLE_ID + 14,
  411. /* p   */    K_ARTICLE_ID + 15,
  412. /* q   */    K_ARTICLE_ID + 16,
  413. /* r   */    K_ARTICLE_ID + 17,
  414. /* s   */    K_ARTICLE_ID + 18,
  415. /* t   */    K_ARTICLE_ID + 19,
  416. /* u   */    K_ARTICLE_ID + 20,
  417. /* v   */    K_ARTICLE_ID + 21,
  418. /* w   */    K_ARTICLE_ID + 22,
  419. /* x   */    K_ARTICLE_ID + 23,
  420. /* y   */    K_ARTICLE_ID + 24,
  421. /* z   */    K_ARTICLE_ID + 25,
  422. /* {   */    K_UNBOUND,
  423. /* |   */    K_UNBOUND,
  424. /* }   */    K_UNBOUND,
  425. /* ~   */        K_UNSELECT_ALL,
  426. /* DEL */        K_PREV_LINE,
  427. /* 200 */    K_UNBOUND,
  428. /* up  */        K_PREV_LINE,
  429. /* down */        K_NEXT_LINE,
  430. /* left */    K_UNBOUND,
  431. /* right */    K_UNBOUND,
  432. /* #0  */    K_UNBOUND,
  433. /* #1  */    K_UNBOUND,
  434. /* #2  */    K_UNBOUND,
  435. /* #3  */    K_UNBOUND,
  436. /* #4  */    K_UNBOUND,
  437. /* #5  */    K_UNBOUND,
  438. /* #6  */    K_UNBOUND,
  439. /* #7  */    K_UNBOUND,
  440. /* #8  */    K_UNBOUND,
  441. /* #9  */    K_UNBOUND,
  442. /* mouse d1 */   K_M_SELECT,
  443. /* mouse d2 */   K_M_PREVIEW,
  444. /* mouse d3 */   K_NEXT_GROUP_NO_UPDATE,
  445. /* mouse u1 */   K_M_SELECT_RANGE,
  446. /* mouse u2 */   K_INVALID,
  447. /* mouse u3 */   K_INVALID
  448. };
  449.  
  450. export int orig_menu_map[KEY_MAP_SIZE];    /* initially empty */
  451.  
  452.  
  453. static struct command_name_map {
  454.     char *    cmd_name;
  455.     int       cmd_code;
  456.     int          cmd_restriction;
  457. } command_name_map[] = {
  458.  
  459.     "advance-article",        K_FORW_ARTICLE,        K_ONLY_MORE,
  460.     "advance-group",        K_ADVANCE_GROUP,    0,
  461.     "article",            K_ARTICLE_ID,        K_ONLY_MENU,
  462.     "as",            K_EQUAL_KEY,        0,
  463.  
  464.     "back-article",        K_BACK_ARTICLE,        K_ONLY_MORE,
  465.     "back-group",        K_BACK_GROUP,        0,
  466.  
  467.     "cancel",            K_CANCEL,        0,
  468.     "close-subject",        K_CLOSE_SUBJECT,    K_ONLY_MENU,
  469.     "command",            K_EXTENDED_CMD,        0,
  470.     "compress",            K_COMPRESS,        K_ONLY_MORE,
  471.     "continue",            K_CONTINUE,        0,
  472.     "continue-no-mark",        K_CONTINUE_NO_MARK,    K_ONLY_MENU,
  473.  
  474.     "decode",            K_UUDECODE,        0,
  475.  
  476.     "find",            K_GOTO_MATCH,        0,
  477.     "find-next",        K_NEXT_MATCH,        K_ONLY_MORE,
  478.     "follow",            K_FOLLOW_UP,        0,
  479.     "full-digest",        K_FULL_DIGEST,        K_ONLY_MORE,
  480.  
  481.     "goto-group",        K_GOTO_GROUP,        0,
  482.     "goto-menu",        K_BACK_TO_MENU,        K_ONLY_MORE,
  483.  
  484.     "help",            K_HELP,            0,
  485.  
  486.     "junk-articles",        K_JUNK_ARTICLES,    K_ONLY_MENU,
  487.  
  488.     "kill-select",        K_KILL_HANDLING,    0,
  489.  
  490.     "layout",            K_LAYOUT,        K_ONLY_MENU,
  491.     "leave-article",        K_LEAVE_ARTICLE,    K_ONLY_MORE,
  492.     "leave-next",        K_LEAVE_NEXT,        K_ONLY_MORE,
  493.     "line+1",            K_NEXT_LINE,        0,
  494.     "line-1",            K_PREV_LINE,        K_ONLY_MENU,
  495.     "line=@",            K_GOTO_LINE,        K_ONLY_MORE,
  496.  
  497.     "macro",            K_MACRO,        0,
  498.     "mail",            K_MAIL_OR_FORWARD,    0,
  499.     "message",            K_LAST_MESSAGE,        0,
  500.     "mouse-continue",        K_M_CONTINUE,        K_ONLY_MORE,
  501.     "mouse-preview",        K_M_PREVIEW,        K_ONLY_MENU,
  502.     "mouse-select",        K_M_SELECT,        K_ONLY_MENU,
  503.     "mouse-select-range",    K_M_SELECT_RANGE,    K_ONLY_MENU,
  504.     "mouse-select-subject",    K_M_SELECT_SUBJECT,    K_ONLY_MENU,
  505.     "mouse-toggle",        K_M_TOGGLE,        0,
  506.  
  507.     "next-article",        K_NEXT_ARTICLE,        K_ONLY_MORE,
  508.     "next-group",        K_NEXT_GROUP_NO_UPDATE,    0,
  509.     "next-subject",        K_NEXT_SUBJECT,        K_ONLY_MORE,
  510.     "nil",            K_UNBOUND,        0,
  511.  
  512.     "open-subject",        K_OPEN_SUBJECT,        K_ONLY_MENU,
  513.     "overview",            K_GROUP_OVERVIEW,    0,
  514.  
  515.     "page+1",            K_NEXT_PAGE,        0,
  516.     "page+1/2",            K_NEXT_HALF_PAGE,    K_ONLY_MORE,
  517.     "page-1",            K_PREV_PAGE,        0,
  518.     "page-1/2",            K_PREV_HALF_PAGE,    K_ONLY_MORE,
  519.     "page=$",            K_LAST_PAGE,        0,
  520.     "page=0",            K_HEADER_PAGE,        0,
  521.     "page=1",            K_FIRST_PAGE,        0,
  522.     "page=@",            K_GOTO_PAGE,        K_ONLY_MORE,
  523.  
  524.     "patch",            K_PATCH,        0,
  525.     "pgp",            K_PGP,                K_ONLY_MORE,
  526.     "post",            K_POST,            0,
  527.     "prefix",            K_PREFIX_KEY,        0,
  528.     "preview",            K_PREVIEW,        0,
  529.     "previous",            K_PREVIOUS,        0,
  530.     "print",            K_PRINT,        0,
  531.  
  532.     "quit",            K_QUIT,            0,
  533.  
  534.     "read-return",        K_READ_GROUP_THEN_SAME,    K_ONLY_MENU,
  535.     "read-skip",        K_READ_GROUP_UPDATE,    0,
  536.     "redraw",            K_REDRAW,        0,
  537.     "reload",                 K_RELOAD,               K_ONLY_MENU,
  538.     "reply",            K_REPLY,        0,
  539.     "rot13",            K_ROT13,        K_ONLY_MORE,
  540.  
  541.     "save-body",        K_SAVE_NO_HEADER,    0,
  542.     "save-full",        K_SAVE_FULL_HEADER,    0,
  543.     "save-short",        K_SAVE_SHORT_HEADER,    0,
  544.     "select",            K_SELECT,        K_ONLY_MENU,
  545.     "select-auto",        K_AUTO_SELECT,        K_ONLY_MENU,
  546.     "select-invert",        K_SELECT_INVERT,    K_ONLY_MENU,
  547.     "select-range",        K_SELECT_RANGE,        K_ONLY_MENU,
  548.     "select-subject",        K_SELECT_SUBJECT,    0,
  549.     "shell",            K_SHELL,        0,
  550.     "skip-lines",        K_SKIP_LINES,        0,
  551.  
  552.     "unselect-all",        K_UNSELECT_ALL,        K_ONLY_MENU,
  553.     "unshar",            K_UNSHAR,        0,
  554.     "unsub",            K_UNSUBSCRIBE,        0,
  555.  
  556.     "version",            K_VERSION,        0,
  557.  
  558.     (char *)NULL,        0,            0
  559. };
  560.  
  561. static int name_map_size;
  562. #define max_cmd_name_length 16    /* recalculate if table is changed */
  563.  
  564. export key_type global_key_map[KEY_MAP_SIZE];
  565.  
  566.  
  567. void
  568. init_key_map()
  569. {
  570.     register int c;
  571.     register struct command_name_map *cnmp;
  572.  
  573.     for (c = 0; c < KEY_MAP_SIZE; c++) global_key_map[c] = c;
  574.     for (c = NORMAL_KEYS+ARROW_KEYS+MULTI_KEYS; c < KEY_MAP_SIZE; c++) {
  575.     menu_key_map[c] = K_UNBOUND;
  576.     more_key_map[c] = K_UNBOUND;
  577.     }
  578.  
  579.     for (cnmp = command_name_map; cnmp->cmd_name; cnmp++);
  580.     name_map_size = cnmp - command_name_map;
  581. }
  582.  
  583.  
  584. int
  585. lookup_command(command, restriction)
  586. char *command;
  587. int restriction;
  588. {
  589.     register struct command_name_map *cnmp;
  590.     register i, j, k, t;
  591.  
  592.     i = 0; j = name_map_size - 1;
  593.  
  594.     while (i <= j) {
  595.     k = (i + j) / 2;
  596.     cnmp = &command_name_map[k];
  597.  
  598.     if ( (t=strcmp(command, cnmp->cmd_name)) > 0)
  599.         i = k+1;
  600.     else
  601.     if (t < 0)
  602.         j = k-1;
  603.     else {
  604.         switch (restriction) {
  605.          case K_ONLY_MENU:
  606.          case K_ONLY_MORE:
  607.         if (cnmp->cmd_restriction == restriction) break;
  608.         /*FALLTHRU*/
  609.          case 0:
  610.         if (cnmp->cmd_restriction == 0) break;
  611.         return K_INVALID-1;
  612.          default:
  613.         break;
  614.         }
  615.         return cnmp->cmd_code;
  616.     }
  617.     }
  618.  
  619.     return K_INVALID;
  620. }
  621.  
  622.  
  623. int
  624. cmd_completion(path, cmd_index)
  625. char *path;
  626. int cmd_index;
  627. {
  628.     static char *head, *tail = NULL;
  629.     static int len;
  630.     static struct command_name_map *cmd, *help_cmd;
  631.  
  632.     if (cmd_index < 0) return 0;
  633.  
  634.     if (path) {
  635.     head = path;
  636.     tail = path + cmd_index;
  637.     while (*head && isspace(*head)) head++;
  638.     help_cmd = cmd = command_name_map;
  639.     len = tail - head;
  640.  
  641.     return 1;
  642.     }
  643.  
  644.     if (cmd_index) {
  645.     list_completion((char *)NULL);
  646.  
  647.     if (help_cmd->cmd_name == NULL)
  648.         help_cmd = command_name_map;
  649.  
  650.     for (;help_cmd->cmd_name; help_cmd++) {
  651.         cmd_index = strncmp(help_cmd->cmd_name, head, len);
  652.         if (cmd_index < 0) continue;
  653.         if (cmd_index > 0) {
  654.         help_cmd = command_name_map;
  655.         break;
  656.         }
  657.         if (list_completion(help_cmd->cmd_name) == 0) break;
  658.     }
  659.     fl;
  660.     return 1;
  661.     }
  662.  
  663.     for (; cmd->cmd_name; cmd++) {
  664.     if (len == 0)
  665.         cmd_index = 0;
  666.     else
  667.         cmd_index = strncmp(cmd->cmd_name, head, len);
  668.     if (cmd_index < 0) continue;
  669.     if (cmd_index > 0) break;
  670.     if (cmd->cmd_code == K_MACRO ||
  671.         cmd->cmd_code == K_ARTICLE_ID ||
  672.         cmd->cmd_code == K_PREFIX_KEY ||
  673.         cmd->cmd_code == K_EQUAL_KEY)
  674.         sprintf(tail, "%s ", cmd->cmd_name + len);
  675.     else
  676.         strcpy(tail, cmd->cmd_name + len);
  677.     cmd++;
  678.     return 1;
  679.     }
  680.     return 0;
  681. }
  682.  
  683.  
  684. char *command_name(cmd)
  685. int cmd;
  686. {
  687.     register struct command_name_map *cnmp;
  688.  
  689.     cmd &= ~GETC_COMMAND;
  690.  
  691.     for (cnmp = command_name_map; cnmp->cmd_name; cnmp++)
  692.     if (cnmp->cmd_code == cmd) return cnmp->cmd_name;
  693.  
  694.     return "unknown";
  695. }
  696.  
  697.  
  698. /*
  699.  * convert key name into ascii code
  700.  *
  701.  *    key names are:
  702.  *        c    character c
  703.  *        ^C    control-C
  704.  *        0xNN    hex value (0..0x7f)
  705.  *        0NNN    octal value (0..0177)
  706.  *        NNN    decimal value (0..127)
  707.  *        up, down, left, rigth    arrow keys
  708.  *        #0..#9            function keys (initially undefined)
  709.  */
  710.  
  711. key_type parse_key(str)
  712. char *str;
  713. {
  714.     int x;
  715.  
  716.     if (str[1] == NUL)
  717.     return (data_bits < 8) ? (str[0] & 0177) : str[0];
  718.  
  719.     if (str[0] == '^')
  720.     if (str[1] == '?')
  721.         return 0177;
  722.     else
  723.         return CONTROL_(str[1]);
  724.  
  725.     if (isdigit(str[0])) {
  726.     if (str[0] == '0')
  727.         if (str[1] == 'x')
  728.         sscanf(str+2, "%x", &x);
  729.         else
  730.         sscanf(str+1, "%o", &x);
  731.     else
  732.         sscanf(str, "%d", &x);
  733.  
  734.     return x;
  735.     }
  736.  
  737.     if (str[0] == '#' && isdigit(str[1]))
  738.     return K_function(str[1] - '0');
  739.  
  740.     if (str[0] == '#') str++;
  741.     
  742.     if (strcmp(str, "space") == 0)
  743.     return SP;
  744.  
  745.     if (strcmp(str, "up") == 0)
  746.     return K_up_arrow;
  747.  
  748.     if (strcmp(str, "down") == 0)
  749.     return K_down_arrow;
  750.  
  751.     if (strcmp(str, "left") == 0)
  752.     return K_left_arrow;
  753.  
  754.     if (strcmp(str, "right") == 0)
  755.     return K_right_arrow;
  756.  
  757.    if (strcmp(str, "mouse_d1") == 0)   /* thp */
  758.     return K_m_d1;
  759.    if (strcmp(str, "mouse_d2") == 0)   /* thp */
  760.     return K_m_d2;
  761.    if (strcmp(str, "mouse_d3") == 0)   /* thp */
  762.     return K_m_d3;
  763.    if (strcmp(str, "mouse_u1") == 0)   /* thp */
  764.     return K_m_u1;
  765.   if (strcmp(str, "mouse_u2") == 0)   /* thp */
  766.     return K_m_u2;
  767.   if (strcmp(str, "mouse_u3") == 0)   /* thp */
  768.     return K_m_u3;
  769.  
  770.     init_message("unknown key: %s", str);
  771.  
  772.     return 0200;
  773. }
  774.  
  775. char *key_name(c)
  776. key_type c;
  777. {
  778.     static char buf[10];
  779.  
  780.     if (c >= NORMAL_KEYS && c <= (key_type)(KEY_MAP_SIZE-NATIONAL_KEYS)) {
  781.     switch (c) {
  782.      case K_up_arrow:
  783.         return "up";
  784.      case K_down_arrow:
  785.         return "down";
  786.      case K_left_arrow:
  787.         return "left";
  788.      case K_right_arrow:
  789.         return "right";
  790.      case K_m_d1:
  791.         return "mouse_d1";
  792.      case K_m_d2:
  793.         return "mouse_d2";
  794.      case K_m_d3:
  795.         return "mouse_d3";
  796.      case K_m_u1:
  797.         return "mouse_u1";
  798.      case K_m_u2:
  799.         return "mouse_u2";
  800.      case K_m_u3:
  801.         return "mouse_u3";
  802.      default:
  803.         buf[0] = '#';
  804.         buf[1] = (c - K_function(0))
  805.         + (c >= (key_type)K_function(MULTI_KEYS) ? 'A'-K_function(MULTI_KEYS) : '0');
  806.         buf[2] = NUL;
  807.         goto out;
  808.     }
  809.     }
  810.  
  811.     if (c == SP)
  812.     return "space";
  813.  
  814.     if (c < SP) {
  815.     buf[0] = '^';
  816.     buf[1] = c + '@';
  817.     buf[2] = NUL;
  818.     goto out;
  819.     }
  820.  
  821.     if (c == 0177) {
  822.     strcpy(buf, "^?");
  823.     goto out;
  824.     }
  825.  
  826.     if (data_bits < 8 && c >= NORMAL_KEYS) {
  827.     sprintf(buf, "0x%02x", c);
  828.     goto out;
  829.     }
  830.  
  831.     buf[0] = c;
  832.     buf[1] = NUL;
  833.  
  834.  out:
  835.     return buf;
  836. }
  837.  
  838.  
  839. void
  840. dump_global_map()
  841. {
  842.     register key_type c;
  843.  
  844.     clrdisp();
  845.     tkb_clear();
  846.     tk("display_Make");
  847.     tkb_so_printf("\1REMAPPED KEYS\1\n\n");
  848.     pg_init(2, 4);
  849.  
  850.     for (c = 0; c < KEY_MAP_SIZE; c++)
  851.     if (c != global_key_map[c]) {
  852.         if (pg_next() < 0) break;
  853.         tkb_tprintf("%s", key_name(c));
  854.         pg_indent(6);
  855.         tkb_tprintf("-> %s", key_name(global_key_map[c]));
  856.     }
  857.  
  858.     tkb_display();
  859.     pg_end();
  860. }
  861.  
  862. int
  863. dump_key_map(where)
  864. char *where;
  865. {
  866.     register struct command_name_map *cnmp;
  867.     register key_type c;
  868.     register int code, first_prt;
  869.     int *map, restriction;
  870.     
  871.     tkb_clear();
  872.     tk("display_Make");
  873.     if ((code = lookup_keymap(where)) < 0) return -1;
  874.     map = keymaps[code].km_map;
  875.     restriction = keymaps[code].km_flag & (K_ONLY_MENU | K_ONLY_MORE);
  876.  
  877.     clrdisp();
  878.     tkb_so_printf("\1KEY BINDINGS (%s)\1\n\n", where);
  879.  
  880.     if (restriction == K_ONLY_MENU) {
  881.     tkb_tprintf("\rarticle:  ");
  882.     for (c = 0; c < KEY_MAP_SIZE; c++)
  883.         if (map[c] & K_ARTICLE_ID) tkb_tprintf("%s", key_name(c));
  884.     }
  885.  
  886.     pg_init(4, 2);
  887.  
  888.     for (cnmp = command_name_map; cnmp->cmd_name; cnmp++) {
  889.     if (cnmp->cmd_restriction && cnmp->cmd_restriction != restriction)
  890.         continue;
  891.     if (cnmp->cmd_code == K_UNBOUND) continue;
  892.     if (cnmp->cmd_code == K_MACRO) continue;
  893.  
  894.     code = cnmp->cmd_code;
  895.     first_prt = 1;
  896.  
  897.     for (c = 0; c < KEY_MAP_SIZE; c++)
  898.         if (map[c] == code) {
  899.         if (first_prt) {
  900.                    tkb_c('\n');
  901.             if (pg_next() < 0) goto out;
  902.             tkb_tprintf("%s", cnmp->cmd_name);
  903.             pg_indent(max_cmd_name_length);
  904.             first_prt = 0;
  905.         }
  906.         tkb_tprintf(" %s", key_name(c));
  907.         }
  908.       tkb_display();
  909.     }
  910.  
  911.     for (c = 0; c < KEY_MAP_SIZE; c++)
  912.     if (map[c] & K_MACRO) {
  913.         if (pg_next() < 0) goto out;
  914.         tkb_c('\n');
  915.         tkb_tprintf("macro %d: %s", (map[c] & ~K_MACRO), key_name(c));
  916.         if (map == menu_key_map && orig_menu_map[c] != K_UNBOUND) 
  917.         tkb_tprintf(" (%s)", command_name(orig_menu_map[c]));
  918.     }
  919.     else if (map[c] & K_PREFIX_KEY) {
  920.         if (pg_next() < 0) goto out;
  921.         tkb_c('\n');
  922.         tkb_tprintf("prefix %s: %s",
  923.            keymaps[(map[c] & ~K_PREFIX_KEY)].km_name, key_name(c));
  924.     }
  925.     tkb_display();
  926.  
  927.  out:
  928.     pg_end();
  929.     return 0;
  930. }
  931.  
  932. #define MAX_KEYMAPS    17
  933.  
  934. struct key_map_def keymaps[MAX_KEYMAPS+1] = {
  935.     "#",    NULL,        K_MULTI_KEY_MAP,
  936.     "key",    NULL,        K_GLOBAL_KEY_MAP,
  937.     "menu",    menu_key_map,    K_BIND_ORIG | K_ONLY_MENU,
  938.     "show",    more_key_map,    K_ONLY_MORE,
  939.     "both",    menu_key_map,    K_BOTH_MAPS | K_BIND_ORIG,
  940.     "more",    more_key_map,    K_ONLY_MORE,
  941.     "read",    more_key_map,    K_ONLY_MORE,
  942.     NULL,
  943. };
  944.  
  945. int
  946. lookup_keymap(name)
  947. char *name;
  948. {
  949.     register struct key_map_def *m;
  950.     
  951.     if (name[0] == '#') return 0;
  952.     
  953.     for (m = keymaps; m->km_name; m++) {
  954.     if (strcmp(name, m->km_name) == 0) return m - keymaps;
  955.     }
  956.     return keymaps - m;
  957. }
  958.  
  959. int
  960. make_keymap(name)
  961. char *name;
  962. {
  963.     register struct key_map_def *m;
  964.     register int *kp;
  965.     int ix;
  966.     
  967.     ix = lookup_keymap(name);
  968.     if (ix >= 0) return -1;
  969.     ix = -ix;
  970.     if (ix == MAX_KEYMAPS) return -2;
  971.     
  972.     m = &keymaps[ix];
  973.     m->km_name = copy_str(name);
  974.     m->km_map = newobj(int, KEY_MAP_SIZE);
  975.     m->km_flag = K_ONLY_MORE | K_ONLY_MENU;
  976.     for (kp = m->km_map; kp < &(m->km_map)[KEY_MAP_SIZE]; ) *kp++ = K_UNBOUND;
  977.  
  978.     return ix;
  979. }
  980.  
  981. int
  982. keymap_completion(buf, ix)
  983. char *buf;
  984. int ix;
  985. {
  986.     static char *head, *tail = NULL;
  987.     static int len;
  988.     static struct key_map_def *map, *help_map;
  989.  
  990.     if (ix < 0) return 0;
  991.  
  992.     if (buf) {
  993.     head = buf;
  994.     tail = buf + ix;
  995.     while (*head && isspace(*head)) head++;
  996.     help_map = map = keymaps;
  997.     len = tail - head;
  998.  
  999.     return 1;
  1000.     }
  1001.  
  1002.     if (ix) {
  1003.     list_completion((char *)NULL);
  1004.  
  1005.     if (help_map->km_name == NULL)
  1006.         help_map = keymaps;
  1007.  
  1008.     for (;help_map->km_name; help_map++) {
  1009.         if (strncmp(help_map->km_name, head, len)) continue;
  1010.         if (list_completion(help_map->km_name) == 0) break;
  1011.     }
  1012.     fl;
  1013.     return 1;
  1014.     }
  1015.  
  1016.     for (; map->km_name; map++) {
  1017.     if (len && strncmp(map->km_name, head, len)) continue;
  1018.     strcpy(tail, map->km_name + len);
  1019.     if (map != keymaps) strcat(tail, " ");
  1020.     map++;
  1021.     return 1;
  1022.     }
  1023.     return 0;
  1024. }
  1025.